package app.utils;

import io.netty.util.internal.PlatformDependent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @description: 堆外内存溢出检测代码
 * @return:
 * @author: sujun
 * @time: 2021/11/9 17:10
 */

@Slf4j
@Service
public class DirectMemoryReporter {

    private static final int _1k = 1024;

    private static final String BUSINESS_KEY = "netty_direct_memory";

    private AtomicLong directMemory;

    @PostConstruct
    public void init() {

        Field field = ReflectionUtils.findField(PlatformDependent.class, "DIRECT_MEMORY_COUNTER");
        field.setAccessible(true);

        try {
            directMemory = (AtomicLong) field.get(PlatformDependent.class);
            startReport();
        } catch (Exception e) {
            log.error("netty_direct_memory error", e);
        }
    }

    public void startReport() {
        Runnable doReport = this::doReport;
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        //第2个参数为首次执行的延迟时间，第3个参数为定时执行的间隔时间
        service.scheduleAtFixedRate(doReport, 1, 300, TimeUnit.SECONDS);
    }


    public void doReport() {

        try {
            //新方法
//            long memoryInKB1 = PlatformDependent.usedDirectMemory();
//            log.warn("{}: {}kb", BUSINESS_KEY, memoryInKB1 / _1k);
            int memoryInKB = (int) directMemory.get();
            log.info("堆外内存 {}: {}kb", BUSINESS_KEY, memoryInKB / _1k);

        } catch (Exception e) {
            log.error("netty_direct_memory error", e);
        }

    }


}